import Vue from 'vue'
import request from './request'

// 不要覆盖继承的属性

// 自选方式 如果需要可以移植
export class Store2 {
  constructor(data = []) {
    // 分页器是独立组件应有自己的数据状态 this.view是table组件的数据状态
    this.filterParams = {
      page: 1,
      pageSize: 10
    }

    this.view = Vue.observable({
      data,
      page: 1,
      pageSize: 10,
      total: 0,
      status: 0,
      loading: false
    })

    // 上一次成功的数据 用于数据请求失败时进行数据回滚
    this.lastSuccessData = {}

    this.lastSuccess = {}

    this._isNeedLoad = false

    // 在created这个时机执行 this.store.load 这个函数 由于生命周期的问题同步任务先执行 微任务并未执行 -> 导致this.proxy.load这个函数为空
    // 但是在visible这个时机 同步任务与微任务已经执行完毕 在执行this.proxy.load这个函数就不会出错
    // 主要的问题就是同步异步问题导致的this.proxy.load为空的情况
    Promise.resolve().then(() => {
      if (this.proxy.type === 'axiosProxy') {
        this.proxy = new AxiosProxy(this.proxy, this)
      } else {
        this.proxy = new CacheProxy(this.proxy, this)
      }
      // 同步执行代码中并未发送请求所以要在微任务中执行请求
      if (this._isNeedLoad) {
        this.proxy.load(this.filter, this.filterParams)
      }
    })
  }

  // table数据请求
  loadData(params) {
    // 所以我要在这个地方进行判断 如果有this.proxy.load这个函数是否存在 存在就是visible的加载时机 直接执行即可
    // 反之就是created的加载时机创建一个标志 在微任务执行时帮助执行this.proxy.load这个函数获取数据
    this.filter = params || {}
    if (this.proxy.load) {
      return this.proxy.load(this.filter, this.filterParams)
    } else {
      this._isNeedLoad = true
    }
  }
  // 分页器请求
  async loadPage(params) {
    this.filterParams.page = params.page || 1
    this.filterParams.pageSize = params.pageSize || 10
    this.loadData()
  }
  // 取消请求
  abort() {
    this.proxy.abort()
  }
  get status() {
    return this.view.status
  }
}
// 正常请求 和 缓存请求 但是处理时应由具体的模型确定(选用)
export class AxiosProxy {
  constructor(config, store) {
    this.url = config.url || ''
    this.view = store.view
    this.controller = null
  }

  async load(filter, filterParams) {
    // 上一次请求为返回结果 忽略上一次请求
    if (this.controller && this.view.status) {
      this.controller.abort()
      this.view.status = 1
    }
    this.controller = new AbortController()
    const signal = this.controller.signal

    this.view.status = 1

    try {
      const { data } = await request.get(this.url, {
        params: {
          // 数据序列化
          ...this.setLoadPage(filterParams),
          ...filter
        },
        signal
      })

      if (filterParams.page === 3) {
        this.view.status = 3
        return
      }

      if (this.getSuccess(data)) {
        // 修改状态码
        this.view.status = 2
        // 修改数据状态
        Object.assign(this.view, {
          data: this.getData(data),
          page: this.getPage(data),
          pageSize: this.getPageSize(data),
          total: this.getTotal(data)
        })
      }
    } catch (error) {
      // 根据axios的不同错误信息进行处理
      if (ErrorCodeHandle[error.code]) {
        ErrorCodeHandle[error.code](this)
      }
    }
  }
  // 主动取消请求
  abort() {
    if (this.controller) {
      this.controller.abort()
    }
  }

  // 复用axios成功解析逻辑
  getSuccess(res) {
    return res?.status === 200
  }
  getData(res) {
    return res?.data?.data || []
  }
  getPage(res) {
    return res?.data?.page || 1
  }
  getPageSize(res) {
    return res?.data?.pageSize || 10
  }
  getTotal(res) {
    return res?.data?.total || 0
  }
  setLoadPage(filterParams) {
    return {
      P: filterParams.page,
      PS: filterParams.pageSize
    }
  }
}

export class CacheProxy extends AxiosProxy {
  async load(params) {
    // 上一个请求可以取消 并且 请求为完成
    if (this.controller && this.view.status === 1) {
      this.controller.abort()
    }
    this.controller = new AbortController()
    const signal = this.controller.signal

    this.view.status = 1

    // 标志位代表是否需要重新请求
    let isInit = false
    // 如果存在申请过的数据就直接返回
    if (this.loaclData) {
      Object.assign(this.view, this.loaclData)
    } else {
      isInit = true
    }
    try {
      if (isInit) {
        this.view.status = 1
      }
      // 新的请求会放在缓存中等待合并
      const { data } = await request.get(this.url, {
        ...params,
        signal
      })

      if (this.getSuccess(data)) {
        if (isInit) {
          this.view.status = 2
        }
        this.loaclData = {
          data: this.getData(data),
          page: this.getPage(data),
          pageSize: this.getPageSize(data),
          total: this.getTotal(data)
        }
        if (isInit) {
          Object.assign(this.view, this.loaclData)
        }
      }
    } catch (error) {
      if (isInit) {
        this.view.status = 3
      }
      console.log(error)
    }
  }
}

export class Model {
  constructor(data = {}) {
    this.view = Vue.observable({
      data
    })
  }

  // 查指定数据
  async findData(id) {
    this.status = 1
    try {
      const { data } = await request.get(this.proxy.action.findDataUrl)
      if (data.status === 200) {
        this.status = 2
        this.data = data.data
      }
    } catch (e) {
      this.status = 3
      console.log(e)
    }
  }
  // 新增数据
  async editorData(params) {
    this.status = 1
    try {
      const { data } = await request.get(this.proxy.action.findDataUrl, { params })
      if (data.status === 200) {
        this.status = 2
        this.data = data.data
      }
    } catch (e) {
      this.status = 3
      console.log(e)
    }
  }

  get data() {
    return this.view.data
  }
  set data(newVal) {
    this.view.data = newVal
  }
}

// 策略模式 代替 if 可以抽离
const ErrorCodeHandle = {
  // 请求错误
  ERR_BAD_REQUEST: intance => {
    Object.assign(intance.view, {
      data: intance.getData(),
      page: intance.getPage(),
      pageSize: intance.getPageSize(),
      total: intance.getTotal()
    })
    intance.view.status = 3
  },
  // 取消请求
  ERR_CANCELED: intance => {
    // 加载状态应该改为请求中
    intance.view.status = 1
  }
}
